
* Packages
ssc install concord, replace
ssc install labutil, replace
net install cleanplots, from("https://tdmize.github.io/data") replace
ssc install heatplot, replace
ssc install palettes, replace
ssc install colrspace, replace
ssc install interflex, replace

* Covariates macro
global covars = "gender_female_imp age_30_44_imp age_45_64_imp age_65plus_imp degree_imp interested_imp gevote20192_imp"



*****************************************************
** SECTION 4: COMPARING CANDIDATE AND PARTY POSITIONS
*****************************************************

* Open data
use "Candidate_Party_Positions.dta", replace

* Preparations
gen n = _n in 1/28
gen issue = "1 (Health)" if n == 1
replace issue = "2 (Health)" if n == 2
replace issue = "3 (Health)" if n == 3
replace issue = "4 (Covid-19)" if n == 4
replace issue = "5 (Covid-19)" if n == 5
replace issue = "6 (Covid-19)" if n == 6
replace issue = "7 (Taxes)" if n == 7
replace issue = "8 (Redistribution)" if n == 8
replace issue = "9 (Taxes)" if n == 9
replace issue = "10 (Gender)" if n == 10
replace issue = "11 (Redistribution)" if n == 11
replace issue = "12 (Cannabis)" if n == 12
replace issue = "13 (Independence)" if n == 13
replace issue = "14 (Autonomy)" if n == 14
replace issue = "15 (Autonomy)" if n == 15
replace issue = "16 (Brexit)" if n == 16
replace issue = "17 (Education)" if n == 17
replace issue = "18 (Education)" if n == 18
replace issue = "19 (Education)" if n == 19
replace issue = "20 (Housing)" if n == 20
replace issue = "21 (Housing)" if n == 21
replace issue = "22 (Transport)" if n == 22
replace issue = "23 (Transport)" if n == 23
replace issue = "24 (Transport)" if n == 24
replace issue = "25 (Environment)" if n == 25
replace issue = "26 (Environment)" if n == 26
replace issue = "27 (Language)" if n == 27
replace issue = "28 (Immigration)" if n == 28
gen r = .
gen C_b = .
gen ccc = .
forvalues i = 1/28 {
qui: corr qs`i'_party qs`i'_cand
replace r = `r(rho)' if n == `i'
qui: concord qs`i'_party qs`i'_cand
replace C_b = `r(C_b)' if n == `i'
replace ccc = `r(rho_c)' if n == `i'
}


* Summary statistics
sum r, detail
sum ccc, detail

* Ranked bar charts
sort r
gen y_r = _n in 1/28
labmask y_r, values(issue)
twoway (bar r y_r, horizontal barwidth(0.6)), title("Pearson Correlation Coefficient", margin(bottom)) ytitle("") yscale(noline) ylabel(1(1)28, noticks labgap(zero) valuelabel nogrid) xtitle("{it:r}") xlabel(0(0.2)1, grid gmin gmax) xmtick(0(0.1)1, nogrid) xsize(4) ysize(4) scale(0.8) scheme(Cleanplots) saving(r.gph, replace)

sort ccc
gen y_ccc = _n in 1/28
labmask y_ccc, values(issue)
twoway (bar ccc y_ccc, horizontal barwidth(0.6)), title("Lin's Concordance Correlation Coefficient", margin(bottom)) ytitle("") yscale(noline) ylabel(1(1)28, noticks labgap(zero) valuelabel nogrid) xtitle("{it:{&rho}{subscript:c}}") xlabel(0(0.2)1, grid gmin gmax) xmtick(0(0.1)1, nogrid) xsize(4) ysize(4) scale(0.8) scheme(Cleanplots) saving(ccc.gph, replace)

graph combine r.gph ccc.gph, scheme(Cleanplots)

erase r.gph 
erase ccc.gph






**************************************************************************
** SECTION 5A: COMPARING CANDIDATE- AND PARTY-LEVEL VAA ADVICE (CONTINOUS)
**************************************************************************


* Open data
use "WLS_Complete.dta", replace // This version of the dataset also includes VAA users that were not exposed to one of the two experimental conditions analyzed in the paper

* Pearson's r
corr adviceCand adviceParty
corr adviceCand adviceParty if cparticipated == 1

* Lin's concordance correlation coefficients
concord adviceCand adviceParty
concord adviceCand adviceParty if cparticipated == 1

* Differences
sum diff_adviceCandParty, detail
tab diff_adviceCandParty
sum diff_adviceCandParty if cparticipated == 1, detail
tab diff_adviceCandParty if cparticipated == 1


* Heat maps
hexplot adviceCand adviceParty, bins(100) ///	
	title("All candidates") ///
	ytitle("Candidate-level advice score", size(medsmall) margin(small)) yscale(noline) ylabel(-100(50)100, angle(horizontal) tlcolor(black)) ///
	xtitle("Party-level advice score", size(medsmall) margin(medsmall)) xscale(noline) xlabel(-100(50)100, tlcolor(black)) ///
	keylabels(, format(%9.2f)) ///
	plotregion(lcolor(black)) aspect(1) xsize(6) ysize(5) scheme(Cleanplots) ///
	addplot(function y = x, yaxis(2) xaxis(2) lcolor(red) range(-100 100) lwidth(medthin) ylabel(-100(50)100,  axis(2) angle(horizontal) tlcolor(black) nolabels) xlabel(-100(50)100, axis(2)angle(horizontal) tlcolor(black) nolabels) ytitle("", axis(2)) xtitle("", axis(2))) 
gr_edit .legend.subtitle.style.editstyle size(small) editcopy
gr_edit .legend.subtitle.text = {}
gr_edit .legend.subtitle.text.Arrpush % of obs.
graph save "heat1.gph", replace

hexplot adviceCand adviceParty if cparticipated == 1, bins(100) ///	
	title("Participating candidates") ///
	ytitle("Candidate-level advice score", size(medsmall) margin(small)) yscale(noline) ylabel(-100(50)100, angle(horizontal) tlcolor(black)) ///
	xtitle("Party-level advice score", size(medsmall) margin(medsmall)) xscale(noline) xlabel(-100(50)100, tlcolor(black)) ///
	keylabels(, format(%9.2f)) ///
	plotregion(lcolor(black)) aspect(1) xsize(6) ysize(5) scheme(Cleanplots) ///
	addplot(function y = x, yaxis(2) xaxis(2) lcolor(red) range(-100 100) lwidth(medthin) ylabel(-100(50)100,  axis(2) angle(horizontal) tlcolor(black) nolabels) xlabel(-100(50)100, axis(2)angle(horizontal) tlcolor(black) nolabels) ytitle("", axis(2)) xtitle("", axis(2))) 
gr_edit .legend.subtitle.style.editstyle size(small) editcopy
gr_edit .legend.subtitle.text = {}
gr_edit .legend.subtitle.text.Arrpush % of obs.
graph save "heat2.gph", replace

graph combine "heat1.gph" "heat2.gph", xsize(10) ysize(5) altshrink note("{it:Note:} The red line represents the line of perfect concordance.", span margin(top)) 

erase "heat1.gph"
erase "heat2.gph"




***********************************************************************
** SECTION 5B: COMPARING CANDIDATE- AND PARTY-LEVEL VAA ADVICE (RANKED)
***********************************************************************


* Open data
use "WLS_Complete.dta", replace // This version of the dataset also includes VAA users that were not exposed to one of the two experimental conditions analyzed in the paper

* Drop a party from a district if it did not run a candidate
drop if cid == .

* Party-based ranking of VAA scores
bysort id: egen rank_party = rank(adviceParty), field

* Candidate-based ranking of VAA scores (using party-based advice scores where candidate-based advice scores are unavailable)
bysort id: egen rank_cand = rank(adviceCand), field

* Correlations between ranks
corr rank_party rank_cand
corr rank_party rank_cand if cparticipated == 1

* Lin's concordance correlation coefficients
concord rank_party rank_cand
concord rank_party rank_cand if cparticipated == 1

* How many users got a different closest match/voting recommendation?
gen diff = 0 if rank_party == 1 & rank_cand == 1
replace diff = 1 if rank_party == 1 & rank_cand != 1
bysort id: egen maxdiff = max(diff)
tab maxdiff if pickone_voter == 1 // 30% in all districts
gen numb_cparticipated = share_cparticipated * numb_candidates
tab maxdiff if pickone_voter == 1 & inrange(numb_cparticipated,1,9) //32% in districts where one or more candidates participated in the candidate survey
tab maxdiff if pickone_voter == 1 & inrange(numb_cparticipated,2,9) //37% in districts where two or more candidates participated in the candidate survey
tab maxdiff if pickone_voter == 1 & inrange(numb_cparticipated,3,9) //43% in districts where three or more candidates participated in the candidate survey






***************************************************************
** SECTION 6.1: ROBUSTNESS CHECKS - CONTINUOUS ISSUE CONGRUENCE
***************************************************************


* Model 1: All candidates
use "WLS_Exp.dta", replace
tab cid, gen(cid_d) // Candidate dummies
reg ptv i.treated##c.adviceCand $covars cid_d*, cl(id) 
gen sample = e(sample) // Sample identifier
interflex ptv treated adviceCand $covars cid_d*, type(kernel) bw(25) cl(id)
global title = "{bf:All candidates}"
global name = "allcand"
qui: do "Marginal_Effects_Kernel.do"


* Model 2: Participating candidates
use "WLS_Exp.dta", replace
tab cid, gen(cid_d) // Candidate dummies
reg ptv i.treated##c.adviceCand $covars cid_d* if cparticipated == 1, cl(id) 
gen sample = e(sample) // Sample identifier
interflex ptv treated adviceCand $covars cid_d* if cparticipated == 1, type(kernel) bw(25) cl(id)
global title = "{bf:Participating candidates}"
global name = "pcand"
qui: do "Marginal_Effects_Kernel.do"


* Model 3: Non-participating candidates
use "WLS_Exp.dta", replace
tab cid, gen(cid_d) // Candidate dummies
reg ptv i.treated##c.adviceCand $covars cid_d* if cparticipated == 0, cl(id) 
gen sample = e(sample) // Sample identifier
interflex ptv treated adviceCand $covars cid_d* if cparticipated == 0, type(kernel) bw(25) cl(id)
global title = "{bf:Non-participating candidates}"
global name = "npcand"
qui: do "Marginal_Effects_Kernel.do"


* Graph combine
graph combine allcand.gph pcand.gph npcand.gph, scheme(Cleanplots) xsize(14) ysize(10) altshrink iscale(*1.7) holes(2)
	* Center top graph
	gr_edit .plotregion1.graph1.xoffset = 70

erase allcand.gph
erase pcand.gph 
erase npcand.gph
erase .pdf





***********************************************
** SECTION 6.2: ROBUSTNESS CHECKS - NO RANK CAP
***********************************************


* Open data
use "WLS_Exp.dta", replace


* Model 1: PTVs & all candidates
reg ptv i.treated##ib10.rank_cand $covars i.cid, cl(id)
estimates store m1

* Model 2: PTVs & participating candidates
reg ptv i.treated##ib9.rank_cand $covars i.cid if cparticipated == 1, cl(id)
estimates store m2

* Model 3: PTVs & non-participating candidates
reg ptv i.treated##ib10.rank_cand $covars i.cid if cparticipated == 0, cl(id)
estimates store m3

* Model 4: Vote intention & all candidates
reg voteint_cand i.treated##ib10.rank_cand $covars i.cid, cl(id)
estimates store m4

* Model 5: Vote intention & participating candidates
reg voteint_cand i.treated##ib9.rank_cand $covars i.cid if cparticipated == 1, cl(id)
estimates store m5

* Model 6: Vote intention & non-participating candidates
reg voteint_cand i.treated##ib10.rank_cand $covars i.cid if cparticipated == 0, cl(id)
estimates store m6

	
* Marginal effects plot
qui: do "Marginal_Effects_NoRankCap.do"





*************************************************
** SECTION 6.3: ROBUSTNESS CHECKS - NO COVARIATES
*************************************************


* Open data
use "WLS_Exp.dta", replace

* Cap rank at 5 for better visiblity
gen rank_cand_capped = rank_cand
replace rank_cand_capped = 5 if inrange(rank_cand,6,10)

* Model 1: PTVs & all candidates
reg ptv i.treated##ib5.rank_cand_capped i.cid, cl(id)
estimates store m1

* Model 2: PTVs & participating candidates
reg ptv i.treated##ib5.rank_cand_capped  i.cid if cparticipated == 1, cl(id)
estimates store m2
	
* Model 3: PTVs & non-participating candidates
reg ptv i.treated##ib5.rank_cand_capped  i.cid if cparticipated == 0, cl(id)
estimates store m3

* Model 4: Vote intention & all candidates
reg voteint_cand i.treated##ib5.rank_cand_capped i.cid, cl(id)
estimates store m4

* Model 5: Vote intention & participating candidates
reg voteint_cand i.treated##ib5.rank_cand_capped i.cid if cparticipated == 1, cl(id)
estimates store m5

* Model 6: Vote intention & non-participating candidates
reg voteint_cand i.treated##ib5.rank_cand_capped i.cid if cparticipated == 0, cl(id)
estimates store m6


* Marginal effects plot
qui: do "Marginal_Effects.do"




***********************************************
** SECTION 6.4: ROBUSTNESS CHECKS - NO SPEEDERS
***********************************************


* Open data
use "WLS_Exp.dta", replace

* Cap rank at 5 for better visiblity
gen rank_cand_capped = rank_cand
replace rank_cand_capped = 5 if inrange(rank_cand,6,10)

* Drop speeders, defined as less users who completed the VAA in less than half of average time (i.e., 458/2 = 229s)
sum totaltime if pickone_voter == 1
local t = `r(mean)' / 2
di `t'
drop if totaltime < `t'


* Model 1: PTVs & all candidates
reg ptv i.treated##ib5.rank_cand_capped $covars i.cid, cl(id)
estimates store m1

* Model 2: PTVs & participating candidates
reg ptv i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 1, cl(id)
estimates store m2
	
* Model 3: PTVs & non-participating candidates
reg ptv i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 0, cl(id)
estimates store m3

* Model 4: Vote intention & all candidates
reg voteint_cand i.treated##ib5.rank_cand_capped $covars i.cid, cl(id)
estimates store m4

* Model 5: Vote intention & participating candidates
reg voteint_cand i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 1, cl(id)
estimates store m5

* Model 6: Vote intention & non-participating candidates
reg voteint_cand i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 0, cl(id)
estimates store m6


* Marginal effects plot
qui: do "Marginal_Effects.do"




	
*******************************************************
** SECTION 6.5: ROBUSTNESS CHECKS - LOGISTIC REGRESSION
*******************************************************


* Open data
use "WLS_Exp.dta", replace

* Cap rank at 5 for better visiblity
gen rank_cand_capped = rank_cand
replace rank_cand_capped = 5 if inrange(rank_cand,6,10)

* Model 1: Vote intention & all candidates - logistic regression
logit voteint_cand i.treated##ib5.rank_cand_capped $covars i.cid, cl(id)
estimates store m1

* Model 2: Vote intention & participating candidates - logistic regression
logit voteint_cand i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 1, cl(id)
estimates store m2

* Model 3: Vote intention & non-participating candidates - logistic regression
logit voteint_cand i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 0, cl(id)
estimates store m3

	
* Marginal effects plot
qui: do "Marginal_Effects_OnlyVoteInt.do"




********************************************
** SECTION 6.6: ROBUSTNESS CHECKS - PTV TIES
********************************************
	

* Open data
use "WLS_Exp.dta", replace
		
* Cap rank at 5 for better visiblity
gen rank_cand_capped = rank_cand
replace rank_cand_capped = 5 if inrange(rank_cand,6,10)


* Model 1: Vote intention & all candidates
reg voteint_cand_noties i.treated##ib5.rank_cand_capped $covars i.cid, cl(id)
estimates store m1

* Model 2: Vote intention & participating candidates
reg voteint_cand_noties i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 1, cl(id)
estimates store m2

* Model 3: Vote intention & non-participating candidates
reg voteint_cand_noties i.treated##ib5.rank_cand_capped $covars i.cid if cparticipated == 0, cl(id)
estimates store m3
	
	
* Marginal effects plot
qui: do "Marginal_Effects_OnlyVoteInt.do"






	
